<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown Editor</title>
    <link rel="stylesheet" href="codemirror/lib/codemirror.css">
    <link rel="stylesheet" href="custom/css/github-markdown.min.css">
    <link rel="stylesheet" href="custom/css/github.min.css">
    <script src="codemirror/lib/codemirror.js"></script>
    <script src="codemirror/mode/markdown/markdown.js"></script>
    <script src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
    <script src="codemirror/mode/xml/xml.js"></script>
    <script src="codemirror/mode/css/css.js"></script>
    <script src="codemirror/mode/javascript/javascript.js"></script>
    <script src="codemirror/mode/python/python.js"></script>
    <script src="codemirror/mode/shell/shell.js"></script>
    <script src="codemirror/mode/powershell/powershell.js"></script>
    <script src="codemirror/addon/edit/continuelist.js"></script>
    <script src="markdown-it/markdown-it.min.js"></script>
    <script src="markdown-it/markdown-it-emoji.min.js"></script>
    <script src="custom/js/highlight.min.js"></script>
    <script src="custom/js/purify.min.js"></script>
    <style>
        :root {
            --color-background: #f6f8fa;
            --color-border: #e1e4e8;
            --color-text: #212529;
        }

        *,
        *::before,
        *::after {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html,
        body {
            height: 100%;
            overflow: hidden;
        }

        body {
            min-height: 100vh;
            font-family: system-ui, -apple-system, sans-serif;
            color: var(--color-text);
            background-color: var(--color-background);
        }

        .container {
            display: flex;
            flex-direction: column;
            height: 100vh;
        }

        header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 5px 20px;
            border-bottom: 1px solid var(--color-border);
            user-select: none;
        }

        header h1 {
            font-size: 18px;
            /* color: var(--color-text); */
        }

        main {
            flex: 1;
            display: flex;
            background: #fff;
            overflow: hidden;
        }

        ul {
            list-style: none;
        }

        .nav {
            display: flex;
            font-size: 14px;
        }

        .nav-item {
            position: relative;
            padding: 0.4rem 0.8rem;
            cursor: pointer;
            border-radius: 4px;
            transition: background 0.2s;
        }

        .nav-item:hover {
            background-color: #e9ecef;
        }

        .nav-item:hover .dropdown-menu {
            display: block;
            background: #e9ecef;
        }

        .dropdown-menu {
            display: none;
            position: absolute;
            top: 100%;
            right: 0;
            min-width: 150px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            border-radius: 6px;
            animation: slideDown 0.3s ease;
            z-index: 100;
        }

        .dropdown-menu.active {
            display: block;
        }

        button {
            background-color: transparent;
            border: none;
            cursor: pointer;
        }

        .menu-item {
            position: relative;
            padding: 0.3rem 1rem 0.3rem 1.3rem;
            color: #212529;
            transition: all 0.2s;
            border-radius: 4px;
            border-bottom: 1px solid #f1f3f5;
        }

        /* 添加左侧竖线 */
        .menu-item::before {
            content: '';
            position: absolute;
            left: 12px;
            top: 50%;
            transform: translateY(-50%);
            width: 2px;
            height: 16px;
            background: #0366d6;
            border-radius: 1px;
            opacity: 0.6;
            transition: opacity 0.2s;
        }

        .menu-item:hover::before {
            background: #d6036c;

        }

        .menu-item:last-child {
            border-bottom: none;
        }

        .menu-item:hover {
            background: #fff;
        }

        .CodeMirror {
            flex: 1;
            min-width: 300px;
            height: 100%;
            font-size: 14px;
            border-right: 2px solid var(--color-border);
        }

        #preview {
            flex: 1;
            background: #fafbfc;
            padding: 10px 16px;
            overflow-y: auto;
            border: none;
        }

        @media (max-width: 800px) {
            main {
                flex-direction: column;
            }

            .CodeMirror {
                min-width: 0;
                border-right: none;
                border-bottom: 2px solid var(--color-border);
                height: 50vh;
            }

            #preview {
                display: none;
            }
        }
    </style>

</head>

<body>
    <div class="container">
        <header>
            <h1>在线 Markdown 编辑器</h1>
            <ul class="nav">
                <li class="nav-item">
                    <button>示例文件</button>
                    <ul class="dropdown-menu" role="menu" id="examplesMenu"></ul>
                </li>
                <li class="nav-item" id="newFile">
                    <button>新建文件</button>
                </li>
                <li class="nav-item" id="openFile">
                    <button>打开文件</button>
                </li>
                <li class="nav-item">
                    <button>保存文件</button>
                    <ul class="dropdown-menu" role="menu" id="saveMenu">
                        <li class="menu-item" id="saveHtml" data-type="html">HTML 格式</li>
                        <li class="menu-item" id="saveMarkdown" data-type="markdown">Markdown 格式</li>
                    </ul>
                </li>
                <li class="nav-item">
                    <button>参考手册</button>
                    <ul class="dropdown-menu" role="menu" id="manualMenu">
                        <li class="menu-item" data-url="https://www.runoob.com/markdown/md-tutorial.html">菜鸟教程</li>
                        <li class="menu-item" data-url="https://www.markdown.cn/">Markdown 中文</li>
                    </ul>
                </li>
            </ul>
        </header>
        <main>
            <textarea id="code" name="code" placeholder="在此输入Markdown内容..."></textarea>
            <div id="preview" class="markdown-body"></div>
        </main>
    </div>
    <script>
        // 初始化编辑器
        const editor = CodeMirror.fromTextArea(document.getElementById('code'), {
            mode: "markdown",
            theme: 'default',
            lineNumbers: true,
            indentWithTabs: false, //使用tab键缩进
            tabSize: 4, //tab键缩进单位
            indentUnit: 4, //缩进单位
            smartIndent: true, //智能缩进
            autofocus: true,
            viewportMargin: Infinity, // 无限视口边距，确保内容始终充满编辑器区域
            extraKeys: {
                "Tab": cm => cm.replaceSelection("    "),
            }
        });

        // markdown-it 配置
        const md = window.markdownit({
            html: false,
            linkify: true,
            typographer: true,
        }).use(window.markdownitEmoji);

        // 预览渲染
        function updatePreview() {
            const content = editor.getValue();
            const rawHtml = md.render(content);
            const preview = document.getElementById('preview');
            const cleanHtml = DOMPurify.sanitize(rawHtml);
            preview.innerHTML = cleanHtml;
            preview.querySelectorAll('pre code:not(.hljs)').forEach(block => {
                hljs.highlightAll();
            });
        }

        editor.on('change', updatePreview);

        // 菜单
        const examples = {
            demo: {
                title: "示例",
                url: "custom/examples/demo.md"
            },
        };

        const examplesMenu = document.getElementById('examplesMenu');
        Object.entries(examples).forEach(([key, example]) => {
            const li = document.createElement('li');
            li.className = 'menu-item';
            li.textContent = example.title;
            li.dataset.exampleKey = key;
            examplesMenu.appendChild(li);
        });

        examplesMenu.addEventListener('click', (event) => {
            const exampleKey = event.target.dataset.exampleKey;
            if (exampleKey && examples[exampleKey]) {
                fetch(examples[exampleKey].url)
                    .then(response => response.text())
                    .then(html => {
                        editor.setValue(html);
                    })
                    .catch(error => console.error('Error loading example:', error));
            }
        });

        document.querySelectorAll('.nav-item').forEach(item => {
            item.addEventListener('mouseenter', () => {
                const menu = item.querySelector('.dropdown-menu');
                const rect = item.getBoundingClientRect();
                if (!menu) return;
                if (rect.right + 150 > window.innerWidth) {
                    menu.style.left = 'auto';
                    menu.style.right = '0';
                } else {
                    menu.style.right = 'auto';
                    menu.style.left = '0';
                }
            });
        });

        // 处理菜单项点击事件
        function loadExample(example) {
            fetch(examples[example].url)
                .then(response => response.text())
                .then(data => {
                    editor.setValue(data);
                })
                .catch(error => console.error('Error loading example:', error));
        };

        manualMenu.addEventListener('click', (event) => {
            const url = event.target.dataset.url;
            if (url) {
                window.open(url, '_blank');
            }
        });

        // 新建文件功能
        document.querySelector('#newFile').addEventListener('click', () => {
            if (editor.getValue() && !confirm('当前内容未保存，确定要新建吗？')) return;
            editor.setValue('');
            localStorage.removeItem('markdown-content');
        });

        // 打开文件功能
        document.querySelector('#openFile').addEventListener('click', () => {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.md';

            input.onchange = e => {
                const file = e.target.files[0];
                if (!file) return;

                const reader = new FileReader();
                reader.onload = () => {
                    editor.setValue(reader.result);
                    showToast(`已打开: ${file.name}`);
                    updatePreview();
                };
                reader.onerror = () => showToast('文件读取失败');
                reader.readAsText(file);
            };

            input.click();
        });

        const saveHtml = document.getElementById('saveHtml');
        const saveMarkdown = document.getElementById('saveMarkdown');

        // 点击菜单项时保存文件
        [saveHtml, saveMarkdown].forEach(item => {
            item.addEventListener('click', () => {
                const type = item.dataset.type; // 获取保存类型 (html/markdown)
                saveFile(type); // 调用保存函数
            });
        });

        // 保存文件的核心逻辑
        function saveFile(type) {
            const content = editor.getValue(); // 获取编辑器内容
            let filename, mimeType;

            // 根据类型设置文件名和 MIME 类型
            if (type === 'html') {
                filename = `document-${Date.now()}.html`;
                mimeType = 'text/html';
            } else if (type === 'markdown') {
                filename = `document-${Date.now()}.md`;
                mimeType = 'text/markdown';
            }

            // 创建 Blob 并触发下载
            const blob = new Blob([content], { type: mimeType });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            a.click();
            URL.revokeObjectURL(url); // 释放内存
        }

        // 图片粘贴上传（Base64）
        editor.getWrapperElement().addEventListener('paste', function (e) {
            const items = e.clipboardData && e.clipboardData.items;
            if (items) {
                for (let i = 0; i < items.length; i++) {
                    if (items[i].type.indexOf('image') !== -1) {
                        const file = items[i].getAsFile();
                        const reader = new FileReader();
                        reader.onload = function (evt) {
                            const imgMarkdown = `![粘贴图片](${evt.target.result})`;
                            editor.replaceSelection(imgMarkdown);
                        };
                        reader.readAsDataURL(file);
                    }
                }
            }
        });

        // 文件拖放上传
        editor.getWrapperElement().addEventListener('drop', function (e) {
            e.preventDefault();
            const files = e.dataTransfer.files;
            if (files && files.length) {
                for (let i = 0; i < files.length; i++) {
                    const file = files[i];

                    // 处理 Markdown 文件
                    if (file.type === 'text/markdown' || file.name.endsWith('.md')) {
                        if (editor.getValue() && !confirm('当前内容未保存，确定要替换吗？')) continue;

                        const reader = new FileReader();
                        reader.onload = function (evt) {
                            editor.setValue(evt.target.result);
                        };
                        reader.readAsText(file);
                        break; // 只处理第一个 Markdown 文件
                    }

                    // 处理图片
                    else if (file.type.indexOf('image') !== -1) {
                        const reader = new FileReader();
                        reader.onload = function (evt) {
                            const imgMarkdown = `![${file.name}](${evt.target.result})`;
                            editor.replaceSelection(imgMarkdown);
                        };
                        reader.readAsDataURL(file);
                    }
                }
            }
        });

        // 滚动同步
        let syncing = false;
        const preview = document.getElementById('preview');
        editor.on('scroll', (cm) => {
            if (syncing) return;
            syncing = true;
            const scrollInfo = cm.getScrollInfo();
            const ratio = scrollInfo.top / (scrollInfo.height - scrollInfo.clientHeight);
            preview.scrollTop = ratio * (preview.scrollHeight - preview.clientHeight);
            syncing = false;
        });

        // 预览滚动同步
        preview.addEventListener('scroll', () => {
            if (syncing) return;
            syncing = true;
            const ratio = preview.scrollTop / (preview.scrollHeight - preview.clientHeight);
            editor.scrollTo(null, ratio * (editor.getScrollInfo().height - editor.getScrollInfo().clientHeight));
            syncing = false;
        });

        // 每10秒自动保存
        setInterval(() => {
            localStorage.setItem('markdown-content', editor.getValue());
        }, 1000 * 60);

        // 启动时恢复
        window.addEventListener('DOMContentLoaded', () => {
            const saved = localStorage.getItem('markdown-content');
            editor.setValue(saved);
        });
    </script>
</body>

</html>